package com.sh.data.engine.domain.normalization.standard.service.impl;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.sh.data.engine.common.constants.HttpStatus;
import com.sh.data.engine.common.constants.code.BizCodes;
import com.sh.data.engine.common.exception.BusinessException;
import com.sh.data.engine.common.exception.InvalidParamException;
import com.sh.data.engine.common.util.DateUtil;
import com.sh.data.engine.common.util.ServletUtils;
import com.sh.data.engine.common.util.excel.EasyExcelUtil;
import com.sh.data.engine.domain.base.model.PageResult;
import com.sh.data.engine.domain.base.model.UserContext;
import com.sh.data.engine.domain.base.model.enums.ThemeEnum;
import com.sh.data.engine.domain.common.model.domain.KeyValueDomain;
import com.sh.data.engine.domain.normalization.research.themedesign.model.domain.ThemeDomain;
import com.sh.data.engine.domain.normalization.research.themedesign.service.ThemeService;
import com.sh.data.engine.domain.normalization.standard.model.domain.*;
import com.sh.data.engine.domain.normalization.standard.model.enums.DataTypeEnum;
import com.sh.data.engine.domain.normalization.standard.model.enums.UnitMeasureEnum;
import com.sh.data.engine.domain.normalization.standard.model.enums.YesOrNoEnum;
import com.sh.data.engine.domain.normalization.standard.model.mapper.*;
import com.sh.data.engine.domain.normalization.standard.model.param.DictionaryOptParam;
import com.sh.data.engine.domain.normalization.standard.model.param.DictionaryParam;
import com.sh.data.engine.domain.normalization.standard.model.param.DictionaryQueryParam;
import com.sh.data.engine.domain.normalization.standard.service.IDictionaryService;
import com.sh.data.engine.domain.util.KeyValueUtil;
import com.sh.data.engine.domain.workspace.manager.service.UserService;
import com.sh.data.engine.repository.dao.normalization.research.themedesign.entity.ThemeEntity;
import com.sh.data.engine.repository.dao.normalization.standard.DictionaryMapper;
import com.sh.data.engine.repository.dao.normalization.standard.DictionaryMappingMapper;
import com.sh.data.engine.repository.dao.normalization.standard.arg.DictionaryArg;
import com.sh.data.engine.repository.dao.normalization.standard.arg.DictionaryQueryArg;
import com.sh.data.engine.repository.dao.normalization.standard.entity.DictionaryEntity;
import com.sh.data.engine.repository.dao.normalization.standard.entity.DictionaryMappingEntity;
import com.sh.data.engine.repository.dao.workspace.index.entity.ProjectEntity;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.SerializationUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @author boyue.wjl
 */
@Service
@Slf4j
public class DictionaryServiceImpl extends ServiceImpl<DictionaryMapper, DictionaryEntity>
    implements IDictionaryService {

    @Autowired
    private DictionaryMapper dictionaryMapper;

    @Autowired
    private DictionaryMappingMapper dictionaryMappingMapper;

    @Autowired
    private ThemeService dictionaryGroupServiceImpl;

    @Autowired
    private UserService userServiceImpl;

//    @Autowired
//    private DataOwnerService departmentService;

    @Autowired
    private ThemeService themeService;

    @Autowired
    private DictionaryItemDomainMapper dictionaryItemDomainMapper;

    @Autowired
    private DictionaryByArgDomianMapper dictionaryByArgDomianMapper;

    @Autowired
    private DictionaryArgMapper dictionaryArgMapper;

    @Autowired
    private DictionaryEntityMapper dictionaryEntityMapper;

    @Autowired
    private DictionaryDetailDomainMapper dictionaryDetailDomainMapper;

    @Autowired
    private DictionaryDomainMapper dictionaryDomainMapper;

    public static final String varPattern = "01";

    public static final String dicCnPattern = "[\\w\\s\\S]{1,128}";

    public static final String dicEnPattern = "[a-zA-Z0-9_]{1,128}";

    @Override
    public PageResult<DictionaryEntity> queryDictionaryEntityPage(DictionaryQueryParam param) {
        String orderField = param.getOrderField();
        String order = param.getOrder();
        if (StringUtils.isBlank(orderField) || Objects.equals(orderField, "updateTimeUnix")) {
            orderField = "updateTime";
        } else if (Objects.equals(orderField, "dictNameEn")) {
            orderField = "dictNameEn";
        }
        if (StringUtils.isBlank(order)) {
            order = "desc";
        }
        Long projectId = param.getProjectId();
        IPage<DictionaryEntity> dictionaryEntityPageResult =
            dictionaryMapper.queryList(
                projectId,
                param.getDictDirIds(),
                param.getSearch(),
                param.getReleaseStatus(),
                orderField,
                order,
                param.getPageSize(),
                param.getPageNum());

        return PageResult.convert(dictionaryEntityPageResult);
    }

    @Override
    public List<DictionaryItemDomain> getListByIds(List<Long> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            return Collections.emptyList();
        }
        return convert2List(dictionaryMapper.getListByIds(ids));
    }

    private List<DictionaryItemDomain> convert2List(List<DictionaryEntity> dictionaryEntityList) {
        List<String> userIds =
            dictionaryEntityList.stream()
                .map(DictionaryEntity::getCreatorId)
                .distinct()
                .collect(Collectors.toList());

        List<Long> departMentId =
            dictionaryEntityList.stream()
                .map(DictionaryEntity::getDepartmentId)
                .distinct()
                .collect(Collectors.toList());

        Map<String, String> userMap = userServiceImpl.getMapByUserIds(userIds);
//        Map<Long, String> mapByDepartMentIdIds =
//            departmentService.getMapByDepartMentIdIds(departMentId);
        List<Long> dictionaryDics =
            dictionaryEntityList.stream()
                .map(DictionaryEntity::getDictDirId)
                .distinct()
                .collect(Collectors.toList());
        Map<Long, ThemeDomain> themeMap = themeService.getMapByIds(dictionaryDics);

        List<DictionaryItemDomain> responseList = new ArrayList<>();
        dictionaryEntityList.forEach(
            dictionaryEntity -> {
                DictionaryItemDomain response = dictionaryItemDomainMapper.map(dictionaryEntity);
                response.setApplicationFrequency(9);
                response.setUpdateTimeUnix(dictionaryEntity.getUpdateTime());
                // response.setCreateUserName(userMap.get(dictionaryEntity.getCreatorId()));
//                response.setAscriptionDepartment(
//                    mapByDepartMentIdIds.get(dictionaryEntity.getDepartmentId()));
                if (Objects.nonNull(dictionaryEntity.getDictDirId())) {
                    response.setDictDirId(dictionaryEntity.getDictDirId());
                    response.setDictDirName(
                        Objects.isNull(themeMap.get(dictionaryEntity.getDictDirId()))
                            ? ""
                            : themeMap.get(dictionaryEntity.getDictDirId()).getThemeName());
                }
                responseList.add(response);
            });
        return responseList;
    }

    @Override
    public List<DictionaryEntity> getListByDictDirIds(List<Long> dictDirIds) {
        if (dictDirIds == null || dictDirIds.isEmpty()) {
            return Lists.newArrayList();
        }
        return dictionaryMapper.getListByDictDirIds(dictDirIds);
    }

    @Override
    public Map<Long, DictionaryEntity> getMapByIds(List<Long> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            return Collections.EMPTY_MAP;
        }
        return dictionaryMapper.getMapByIds(ids);
    }

    @Override
    public List<DictionaryByArgDomian> queryListByArg(DictionaryQueryArg dictionaryQueryArg) {
        //    Query query = new Query();
        //    Criteria criteria =
        //
        // Criteria.where("projectId").is(dictionaryQueryArg.getProjectId()).and("rowState").is(1);
        //    if (Objects.nonNull(dictionaryQueryArg.getReleaseStatus())) {
        //      criteria.and("releaseStatus").is(dictionaryQueryArg.getReleaseStatus());
        //    }
        //    if (CollectionUtils.isNotEmpty(dictionaryQueryArg.getDictDirIds())) {
        //      criteria.and("dictDirId").in(dictionaryQueryArg.getDictDirIds());
        //    }
        //    if (Objects.nonNull(dictionaryQueryArg.getSearch())) {
        //      criteria.andOperator(
        //          new Criteria().and("dictNameCn").regex(dictionaryQueryArg.getSearch()),
        //          new Criteria().and("dictNameEn").regex(dictionaryQueryArg.getSearch()));
        //    }
        //
        //    query.addCriteria(criteria);
        //    if (StringUtils.isNotBlank(dictionaryQueryArg.getOrder())) {
        //      query.with(
        //          Sort.by(
        //              Sort.Direction.fromString(dictionaryQueryArg.getOrder()),
        //              dictionaryQueryArg.getOrderField()));
        //    }
        LambdaQueryWrapper<DictionaryEntity> query = new QueryWrapper<DictionaryEntity>().lambda();
        // fixme 添加orderby 字段
        query
            .eq(DictionaryEntity::getProjectId, dictionaryQueryArg.getProjectId())
            .eq(DictionaryEntity::getRowState, 1)
            .eq(
                Objects.nonNull(dictionaryQueryArg.getReleaseStatus()),
                DictionaryEntity::getReleaseStatus,
                dictionaryQueryArg.getReleaseStatus())
            .in(
                CollectionUtils.isNotEmpty(dictionaryQueryArg.getDictDirIds()),
                DictionaryEntity::getDictDirId,
                dictionaryQueryArg.getDictDirIds())
            .and(
                Objects.nonNull(dictionaryQueryArg.getSearch()),
                i ->
                    i.like(DictionaryEntity::getDictNameEn, dictionaryQueryArg.getSearch())
                        .or()
                        .like(DictionaryEntity::getDictNameCn, dictionaryQueryArg.getSearch()));

        List<DictionaryEntity> dicList = dictionaryMapper.selectList(query);
        Map<String, String> mapByUserIds =
            userServiceImpl.getMapByUserIds(
                dicList.stream().map(i -> i.getCreatorId()).collect(Collectors.toList()));
        List<DictionaryByArgDomian> dictionaryByArgDomians = dictionaryByArgDomianMapper.map(dicList);

        ArrayList<DictionaryByArgDomian> result = Lists.newArrayList();
        dictionaryByArgDomians.forEach(
            i -> {
                Long id = i.getId();
                LambdaQueryWrapper<DictionaryMappingEntity> query2 =
                    new QueryWrapper<DictionaryMappingEntity>().lambda();
                query2
                    .eq(DictionaryMappingEntity::getProjectId, dictionaryQueryArg.getProjectId())
                    .eq(DictionaryMappingEntity::getRowState, 1)
                    .eq(DictionaryMappingEntity::getMapSource, 0)
                    .eq(DictionaryMappingEntity::getDictId, id);
                List<DictionaryMappingEntity> multi = dictionaryMappingMapper.selectList(query2);

                multi.forEach(
                    e -> {
                        DictionaryByArgDomian clone = (DictionaryByArgDomian) SerializationUtils.clone(i);
                        clone.setBoundCount(e.getBoundCount());
                        clone.setNotBoundCount(e.getNotBoundCount());
                        clone.setUpdateTime(e.getUpdateTime());
                        clone.setCreatorName(mapByUserIds.get(clone.getCreatorId()));
                        result.add(clone);
                    });
            });
        return result.stream().distinct().collect(Collectors.toList());
    }

    @Override
    public void batchOpt(String userId, List<Long> ids, Integer optType) {
        List<DictionaryEntity> dictList = dictionaryMapper.getListByIds(ids);
        if (CollectionUtils.isEmpty(dictList)) {
            return;
        }
        if (Objects.equals(optType, 0)) {
            dictList.forEach(
                dict -> {
                    if (!Objects.equals(dict.getReleaseStatus(), 0)) {
                        log.error("未发布字典才可以发布");
                        throw new BusinessException(BizCodes.DICTIONARY_IS_NOT_PUBLISHED, HttpStatus.BAD_REQUEST);
                    }
                });
            dictionaryMapper.releaseByIds(ids, userId, 1, new Date());
        } else if (Objects.equals(optType, 1)) {
            dictList.forEach(
                dict -> {
                    if (Objects.equals(dict.getReleaseStatus(), 1)) {
                        log.error("已发布的字典不可以删除");
                        throw new BusinessException(BizCodes.PUBLISHED_DICTIONARY_NOT_ALLOWED_TO_DELETE, HttpStatus.BAD_REQUEST);
                    }
                });
            dictionaryMapper.deleteByIds(ids, userId, new Date());
        } else if (Objects.equals(optType, 2)) {
            dictList.forEach(
                dict -> {
                    if (!Objects.equals(dict.getReleaseStatus(), 1)) {
                        log.error("已发布字典才可以下线");
                        throw new BusinessException(BizCodes.ONLY_PUBLISHED_DICTIONARY_CAN_BE_RELEASED, HttpStatus.BAD_REQUEST);
                    }
                });
            dictionaryMapper.releaseByIds(ids, userId, 0, new Date());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class, transactionManager = "engineTransactionManager")
    public void importDictionary(List<List<String>> dataList, int headRowNumber) {
        if (CollectionUtils.isEmpty(dataList)) {
            return;
        }

        var projectId = ServletUtils.getProjectId();
        List<String> nameCnList = dictionaryMapper.getDictNameCnByProjectId(projectId);
        List<String> nameEnList =
            dictionaryMapper.getDictNameEnByProjectId(projectId).stream()
                .map(String::toUpperCase)
                .collect(Collectors.toList());

        List<ThemeDomain> primaryThemes = dictionaryGroupServiceImpl.getPrimaryThemes();
        Map<String, ThemeDomain> firstDirMap = getGroupNameMapByPids(primaryThemes, Arrays.asList(0L));

//        Map<String, DataOwnerDomain> departmentMap =
//            departmentService.getAllByProjectId(projectId).stream()
//                .collect(
//                    Collectors.toMap(
//                        DataOwnerDomain::getOwnerName, Function.identity(), (o1, o2) -> o1));

        List<DictionaryParam> dictionaryParamList = new ArrayList<>();
        for (int i = 0; i < dataList.size(); i++) {
            dictionaryParamList.add(
                validateRow(
                    projectId,
                    dataList.get(i),
                    (i + headRowNumber + 1),
                    nameCnList,
                    nameEnList,
                    firstDirMap));
        }
        DictionaryServiceImpl curService =
            SpringUtil.getApplicationContext().getBean(DictionaryServiceImpl.class);
        curService.dictionaryBatchAdd(dictionaryParamList, headRowNumber);
    }

    private Map<String, ThemeDomain> getGroupNameMapByPids(
        List<ThemeDomain> dictionaryGroupList, List<Long> pids) {
        return dictionaryGroupList.stream()
            .filter(t -> pids.contains(t.getPid()))
            .collect(Collectors.toMap(ThemeDomain::getThemeName, Function.identity(), (o1, o2) -> o1));
    }

    @Transactional(rollbackFor = Exception.class, transactionManager = "engineTransactionManager")
    public void dictionaryBatchAdd(List<DictionaryParam> dictionaryParamList, int headRowNumber) {
        for (int i = 0; i < dictionaryParamList.size(); i++) {
            DictionaryParam param = dictionaryParamList.get(i);
            try {
                addDictionary(param);
            } catch (BusinessException e) {
                throw new BusinessException(
                    "第" + (headRowNumber + 1 + i) + "行, 字典中文名或英文名已存在重复");
            } catch (Exception e) {
                log.error("导入错误：", e);
                throw new BusinessException(BizCodes.IMPORT_EXCEL_FILE_ERROR, HttpStatus.INTERNAL_SERVER_ERROR);
            }
        }
    }

    /**
     * 创建分组
     *
     * @param dirMap
     * @param name
     * @param pid
     * @return
     */
    //  private DictionaryGroupDomain createGroup(
    //      Map<String, DictionaryGroupDomain> dirMap, String name, Long pid) {
    //    DictionaryGroupParam groupParam = new DictionaryGroupParam();
    //    groupParam.setPid(pid);
    //    groupParam.setName(name);
    //    DictionaryGroupDomain group = dictionaryGroupServiceImpl.addDictionaryGroup(groupParam);
    //    dirMap.put(group.getName(), group);
    //    return group;
    //  }

    /**
     * 校验
     *
     * @param item
     * @param index
     * @param nameCnList
     * @param nameEnList
     * @param firstDirMap
     * @return
     */
    private DictionaryParam validateRow(
        Long projectId,
        List<String> item,
        int index,
        List<String> nameCnList,
        List<String> nameEnList,
        Map<String, ThemeDomain> firstDirMap) {
        DictionaryParam param = new DictionaryParam();
        param.setReleaseStatus(0);
        param.setDictType(0);
        param.setRemark("");
        param.setPid(0L);

        // 目录
        String title01 = EasyExcelUtil.getValueByIndex(item, 0);
        if (StringUtils.isBlank(title01)) {
            throw new InvalidParamException("第" + index + "行, 一级目录不能为空");
        }
        //    if(!Objects.equals(title01,"公共层")){
        //      throw new InvalidParamException(StatusCode.FAILED, "第" + index + "行, 一级目录只能为“公共层”");
        //    }
        String title02 = EasyExcelUtil.getValueByIndex(item, 1);
        String title03 = EasyExcelUtil.getValueByIndex(item, 2);
        String title04 = EasyExcelUtil.getValueByIndex(item, 3);
        // String title05 = EasyExcelUtil.getValueByIndex(item, 4);
        if (StringUtils.isBlank(title02)
            && (StringUtils.isNotBlank(title03) || StringUtils.isNotBlank(title04))) {
            throw new InvalidParamException("第" + index + "行, 子目录上级目录不能为空");
        }
        if (StringUtils.isBlank(title03) && (StringUtils.isNotBlank(title04))) {
            throw new InvalidParamException("第" + index + "行, 子目录上级目录不能为空");
        }
        //    if (StringUtils.isBlank(title04) && StringUtils.isNotBlank(title05)) {
        //      throw new InvalidParamException(StatusCode.FAILED, "第" + index + "行, 子目录上级目录不能为空");
        //    }

        Long dirId;
        ThemeDomain firstGroup = firstDirMap.get(ThemeEnum.DWD.getName());
        if (firstGroup == null) {
            throw new BusinessException("主题域不存在");
        }
        dirId = firstGroup.getId();

        if (StringUtils.isNotBlank(title01)) {
            ThemeEntity themeIfNotExistCreate =
                dictionaryGroupServiceImpl.getThemeIfNotExistCreate(projectId, title01, dirId);
            dirId = themeIfNotExistCreate.getId();
        }

        if (StringUtils.isNotBlank(title02)) {

            ThemeEntity themeIfNotExistCreate =
                dictionaryGroupServiceImpl.getThemeIfNotExistCreate(projectId, title02, dirId);
            dirId = themeIfNotExistCreate.getId();
        }

        if (StringUtils.isNotBlank(title03)) {

            ThemeEntity themeIfNotExistCreate =
                dictionaryGroupServiceImpl.getThemeIfNotExistCreate(projectId, title03, dirId);
            dirId = themeIfNotExistCreate.getId();
        }
        if (StringUtils.isNotBlank(title04)) {

            ThemeEntity themeIfNotExistCreate =
                dictionaryGroupServiceImpl.getThemeIfNotExistCreate(projectId, title04, dirId);
            dirId = themeIfNotExistCreate.getId();
        }
        param.setDictDirId(dirId);

        // 中文名
        String nameCn = EasyExcelUtil.getValueByIndex(item, 4);
        if (StringUtils.isBlank(nameCn)) {
            throw new InvalidParamException("第" + index + "行, 中文名必填");
        }
        if (nameCnList.contains(nameCn)) {
            throw new InvalidParamException("第" + index + "行, 中文名已存在");
        } else {
            Pattern pattern = Pattern.compile(dicCnPattern);
            Matcher matcher = pattern.matcher(nameCn);
            if (!matcher.find()) {
                throw new BusinessException("第" + index + "行, 中文名不合法");
            }
            param.setDictNameCn(nameCn);
        }

        nameCnList.add(nameCn);

        // 英文名
        String nameEn = EasyExcelUtil.getValueByIndex(item, 5);
        if (StringUtils.isBlank(nameEn)) {
            throw new InvalidParamException("第" + index + "行, 英文名必填");
        }
        if (nameEnList.contains(nameEn.toUpperCase())) {
            throw new InvalidParamException("第" + index + "行, 英文名已存在");
        } else {
            Pattern pattern = Pattern.compile(dicCnPattern);
            Matcher matcher = pattern.matcher(nameCn);
            if (!matcher.find()) {
                throw new BusinessException("第" + index + "行, 英文名不合法");
            }
            param.setDictNameEn(nameEn);
        }

        nameEnList.add(nameEn.toUpperCase());

        // 业务含义
        String bizStr = EasyExcelUtil.getValueByIndex(item, 6);
        if (StringUtils.isNotBlank(bizStr)) {
            List<KeyValueDomain> domainsList = KeyValueUtil.getKeyValueList(bizStr);
            if (domainsList == null) {
                throw new InvalidParamException("第" + index + "行,业务含义不正确");
            }
            // param.setBizPropertiesJson(JSONUtil.toJsonStr(domainsList));
            param.setBizPropertiesJson(JSON.toJSONString(domainsList));
        }

        // 数据类型
        String dictDataTypeStr = EasyExcelUtil.getValueByIndex(item, 7);
        if (StringUtils.isNotBlank(dictDataTypeStr)) {
            DataTypeEnum dataTypeEnum = DataTypeEnum.valueOfDes(dictDataTypeStr);
            if (dataTypeEnum == null) {
                throw new InvalidParamException("第" + index + "行, 数据类型不正确");
            }
            param.setDictDataType(dataTypeEnum.getVal());
        } else {
            throw new InvalidParamException("第" + index + "行, 数据类型必填");
        }

        // 长度
        String dictDataLengthStr = EasyExcelUtil.getValueByIndex(item, 8);
        //    if (StringUtils.isBlank(dictDataLengthStr)) {
        //      throw new InvalidParamException(StatusCode.FAILED, "第" + index + "行, 数据长度必填");
        //    }
        if (StringUtils.isNotBlank(dictDataLengthStr)) {
            Integer dictDataLength = NumberUtil.parseInt(dictDataLengthStr);
            if (dictDataLength == null) {
                throw new InvalidParamException("第" + index + "行, 数据长度非整数类型");
            }
            if (dictDataLength < 1) {
                throw new InvalidParamException("第" + index + "行, 数据长度非正整数");
            }
            param.setDictDataLength(dictDataLength);
        }

        // 度量单位
        String dictDataUnitStr = EasyExcelUtil.getValueByIndex(item, 9);
        if (StringUtils.isNotBlank(dictDataUnitStr)) {
            UnitMeasureEnum unit = UnitMeasureEnum.valueOfDes(dictDataUnitStr);
            if (unit == null) {
                throw new InvalidParamException("第" + index + "行, 度量单位不正确");
            }
            param.setDictDataUnit(unit.getVal());
        }

        // 是否允许为空
        String allowNullStr = EasyExcelUtil.getValueByIndex(item, 10);
        if (StringUtils.isNotBlank(allowNullStr)) {
            YesOrNoEnum yesOrNoEnum = YesOrNoEnum.valueOfDes(allowNullStr);
            if (yesOrNoEnum == null) {
                throw new InvalidParamException("第" + index + "行, 是否允许为空不正确");
            }
            param.setAllowNull(yesOrNoEnum.getVal());
        } else {
            param.setAllowNull(YesOrNoEnum.YES.getVal());
        }

        // 是否允许重复
        param.setAllowDuplicate(YesOrNoEnum.YES.getVal());

        // 枚举范围
        String dictDataEnumValueStr = EasyExcelUtil.getValueByIndex(item, 11);
        if (StringUtils.isNotBlank(dictDataEnumValueStr)) {
            List<KeyValueDomain> domainsList = KeyValueUtil.getKeyValueList(dictDataEnumValueStr);
            if (domainsList == null) {
                throw new InvalidParamException("第" + index + "行,枚举范围不正确");
            }
            // param.setDictDataEnumValueJson(JSONUtil.toJsonStr(domainsList));
            param.setDictDataEnumValueJson(JSON.toJSONString(domainsList));
        }

        // 正则表达式
        String dictDataPatternStr = EasyExcelUtil.getValueByIndex(item, 12);

        param.setDictDataPattern(dictDataPatternStr);

        // 部门
//        String departmentStr = EasyExcelUtil.getValueByIndex(item, 13);
//        if (StringUtils.isBlank(departmentStr)) {
//            throw new InvalidParamException(StatusCode.FAILED, "第" + index + "行, 数据Owner必填");
//        }
//        if (departmentStr != null) {
//            DataOwnerDomain department = departmentMap.get(departmentStr);
//            if (department == null) {
//                DataOwnerSaveNewParam dataOwnerSaveNewParam = new DataOwnerSaveNewParam();
//                dataOwnerSaveNewParam.setOwnerName(departmentStr);
//                dataOwnerSaveNewParam.setOwnerDesc(departmentStr);
//                dataOwnerSaveNewParam.setProjectId(projectId);
//                department = departmentService.saveNewDataOwner(dataOwnerSaveNewParam);
//                departmentMap.put(departmentStr, department);
//            }
//            param.setDepartmentId(department.getId());
//        }
        return param;
    }

    @Override
    public PageResult<DictionaryItemDomain> listDictionary(DictionaryQueryParam param) {
        PageResult<DictionaryEntity> dictionaryPage = queryDictionaryEntityPage(param);
        List<DictionaryEntity> dictionaryEntityList = dictionaryPage.getResult();
        List<String> ids =
            dictionaryEntityList.stream().map(e -> e.getCreatorId()).collect(Collectors.toList());
        Map<String, String> mapByUserIds = userServiceImpl.getMapByUserIds(ids);
        PageResult<DictionaryItemDomain> pageResult = new PageResult<>();
        List<DictionaryItemDomain> dictionaryItemDomains = convert2List(dictionaryEntityList);
        dictionaryItemDomains.forEach(
            e -> {
                e.setCreateUserName(mapByUserIds.get(e.getCreatorId()));
            });
        pageResult.setResult(dictionaryItemDomains);
        pageResult.setPageSize(dictionaryPage.getPageSize());
        pageResult.setPageNum(dictionaryPage.getPageNum());
        pageResult.setTotalPages(dictionaryPage.getTotalPages());
        pageResult.setTotalElements(dictionaryPage.getTotalElements());
        return pageResult;
    }

    private List<DictionaryEntity> getExistDictionary(DictionaryParam param, Long projectId) {
        DictionaryArg arg = dictionaryArgMapper.map(param);
        arg.setProjectId(projectId);
        return dictionaryMapper.getListByArg(arg);
    }

    @Override
    public Boolean addDictionary(DictionaryParam param) {
        var projectId = ServletUtils.getProjectId();
        String userId = UserContext.getUserId();
        String dictDataRangeJson = param.getDictDataRangeJson();
        if (StringUtils.isNotBlank(dictDataRangeJson)) {
            validateRangeJson(dictDataRangeJson);
        }
        List<DictionaryEntity> dictionaryEntities = getExistDictionary(param, projectId);
        if (dictionaryEntities.size() > 0) {
            List<String> nameEnList =
                dictionaryEntities.stream()
                    .map(dict -> dict.getDictNameEn().toUpperCase())
                    .collect(Collectors.toList());
            if (nameEnList.contains(param.getDictNameEn().toUpperCase())) {
                throw new BusinessException(BizCodes.DICT_ENGLISH_NAME_ALREADY_EXISTS_ERROR, HttpStatus.BAD_REQUEST);
            } else {
                throw new BusinessException(BizCodes.DICT_CHINESE_NAME_ALREADY_EXISTS_ERROR, HttpStatus.BAD_REQUEST);
            }
        }

        DictionaryEntity de = dictionaryEntityMapper.map(param);
        ProjectEntity project = new ProjectEntity();
        project.setId(projectId);
        de.setProjectId(projectId);
        de.setRowState(1);
        de.setCreatorId(userId);
        de.setCreateTime(new Date());
        de.setUpdateTime(new Date());
        de.setUpdaterId(userId);
        dictionaryMapper.insert(de);

        param.setId(de.getId());

        return Boolean.TRUE;
    }

    private void validateRangeJson(String rangeJson) {
        DictDataRangeJsonDomain dictDataRangeJsonDomain =
            JSON.parseObject(rangeJson, DictDataRangeJsonDomain.class);
        String valueCondition1 = dictDataRangeJsonDomain.getValueCondition1();
        String valueRange1 = dictDataRangeJsonDomain.getValueRange1();
        String valueJudge = dictDataRangeJsonDomain.getValueJudge();
        String valueCondition2 = dictDataRangeJsonDomain.getValueCondition2();
        String valueRange2 = dictDataRangeJsonDomain.getValueRange2();
        ArrayList<String> values =
            Lists.newArrayList(valueCondition1, valueRange1, valueJudge, valueCondition2, valueRange2);

        /** 00000 11111 10000 01111 1-代表有值 0-代表无值 不能出现01这种顺序组合 */
        Collections.reverse(values);
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < values.size(); i++) {
            if (StringUtils.isNotBlank(values.get(i))) {
                sb.append("1");
            } else {
                sb.append("0");
            }
        }
        Pattern pattern = Pattern.compile(varPattern);
        Matcher matcher = pattern.matcher(sb.toString());
        if (matcher.find()) {
            throw new BusinessException("请求参数【数据范围】入参不合法，请检查请求参数");
        }
    }

    @Override
    public Boolean editDictionary(DictionaryParam param) {
        String userId = UserContext.getUserId();
        var projectId = ServletUtils.getProjectId();

        List<DictionaryEntity> dictionaryEntities = getExistDictionary(param, projectId);
        if (dictionaryEntities.isEmpty()
            || (dictionaryEntities.size() == 1
            && Objects.equals(dictionaryEntities.get(0).getId(), param.getId()))) {
            DictionaryEntity de = dictionaryEntityMapper.map(param);
            de.setUpdaterId(userId);
            de.setUpdateTime(new Date());
            int rowAffected = dictionaryMapper.updateById(de);
            if (rowAffected == 0) {
                throw new BusinessException(BizCodes.DICT_UPDATE_ERROR, HttpStatus.BAD_REQUEST);
            }
            return Boolean.TRUE;
        }

        List<String> nameEnList =
            dictionaryEntities.stream()
                .filter(t -> !Objects.equals(t.getId(), param.getId()))
                .map(dict -> dict.getDictNameEn().toUpperCase())
                .collect(Collectors.toList());
        if (nameEnList.contains(param.getDictNameEn().toUpperCase())) {
            throw new BusinessException(BizCodes.DICT_ENGLISH_NAME_ALREADY_EXISTS_ERROR, HttpStatus.BAD_REQUEST);
        } else {
            throw new BusinessException(BizCodes.DICT_CHINESE_NAME_ALREADY_EXISTS_ERROR, HttpStatus.BAD_REQUEST);
        }
    }

    @Override
    public void deleteDictionary(String userId, DictionaryOptParam param) {
        DictionaryEntity dictionaryEntity = dictionaryMapper.getById(param.getId());
        if (dictionaryEntity == null) {
            return;
        }
        if (Objects.equals(dictionaryEntity.getReleaseStatus(), 1)) {
            throw new BusinessException("已发布的字典不可以删除");
        }

        LambdaUpdateWrapper<DictionaryEntity> update = new UpdateWrapper<DictionaryEntity>().lambda();
        update
            .eq(DictionaryEntity::getId, param.getId())
            .set(DictionaryEntity::getRowState, 0)
            .set(DictionaryEntity::getUpdaterId, userId)
            .set(DictionaryEntity::getUpdateTime, new Date());
        dictionaryMapper.update(null, update);
    }

    @Override
    public void releaseDictionary(String userId, DictionaryOptParam param) {
        DictionaryEntity dictionaryEntity = dictionaryMapper.getById(param.getId());
        if (dictionaryEntity == null) {
            return;
        }
        LambdaUpdateWrapper<DictionaryEntity> update = new UpdateWrapper<DictionaryEntity>().lambda();
        update
            .eq(DictionaryEntity::getId, param.getId())
            .set(DictionaryEntity::getReleaseTime, new Date())
            .set(DictionaryEntity::getUpdateTime, new Date())
            .set(DictionaryEntity::getUpdaterId, userId)
            .set(DictionaryEntity::getReleaseStatus, param.getReleaseStatus());
        dictionaryMapper.update(null, update);
    }

    @Override
    public DictionaryDetailDomain detailDictionary(Long id) {
        DictionaryEntity dictionaryEntity = dictionaryMapper.getById(id);
        return Objects.isNull(dictionaryEntity)
            ? null
            : dictionaryDetailDomainMapper.map(dictionaryEntity);
    }

    public List<DictionaryDomain> getDictionaryByProjectIdAndTaskTime(
        Long projectId, Date lastTaskExecuteTime, Date currentTaskExecuteTime) {
        List<DictionaryEntity> dicts =
            dictionaryMapper.getDictionaryByProjectIdAndLastTaskTime(
                projectId, lastTaskExecuteTime, currentTaskExecuteTime);
        return dictionaryDomainMapper.map(dicts);
    }

    @Override
    public void exportList(List<Long> ids, HttpServletResponse response) {
        List<DictionaryEntity> dictList = dictionaryMapper.getListByIds(ids);

        // 创建人
        List<String> userIds =
            dictList.stream()
                .map(DictionaryEntity::getCreatorId)
                .distinct()
                .collect(Collectors.toList());
        Map<String, String> userMap = userServiceImpl.getMapByUserIds(userIds);

        // 归属部门
//        Map<Long, DataOwnerDomain> departmentMap =
//            departmentService.getMapByIds(
//                dictList.stream()
//                    .map(DictionaryEntity::getDepartmentId)
//                    .distinct()
//                    .collect(Collectors.toList()));

        Map<Long, ThemeDomain> groupMap =
            themeService.getMapByIds(
                dictList.stream().map(DictionaryEntity::getDictDirId).collect(Collectors.toList()));
        List<List<String>> dataList = new ArrayList<>(dictList.size());
        String[] columnNames = {
            "中文名称", "英文名称", "字典目录", "业务属性", "状态", "类型", "数据类型", "数据长度", "度量单位", "允许为空", "允许重复", "取值范围",
            "正则表达式", "枚举值", "更新时间", "创建人"
        };
        dataList.add(Arrays.asList(columnNames));
        dictList.forEach(
            domain -> {
                List<String> item = new ArrayList<>();
                item.add(StringUtils.isBlank(domain.getDictNameCn()) ? "" : domain.getDictNameCn());
                item.add(StringUtils.isBlank(domain.getDictNameEn()) ? "" : domain.getDictNameEn());
                item.add(getGroupName(domain.getDictDirId(), groupMap));
                item.add(getKeyValueStr(domain.getBizPropertiesJson()));
                // item.add(StringUtils.isBlank(domain.getRemark()) ? "" : domain.getRemark());
                item.add(Objects.equals(domain.getReleaseStatus(), 1) ? "已发布" : "待发布");
                item.add(Objects.equals(domain.getDictType(), 0) ? "自建" : "引用");
                item.add(DataTypeEnum.toStringByVal(domain.getDictDataType()));
                item.add(domain.getDictDataLength() == null ? "" : domain.getDictDataLength().toString());
                item.add(UnitMeasureEnum.toStringByVal(domain.getDictDataUnit()));
                item.add(Objects.equals(domain.getAllowNull(), 0) ? "否" : "是");
                item.add(Objects.equals(domain.getAllowDuplicate(), 0) ? "否" : "是");
                item.add(getRangeStr(domain.getDictDataRangeJson()));
                item.add(
                    StringUtils.isBlank(domain.getDictDataPattern()) ? "" : domain.getDictDataPattern());
                item.add(getKeyValueStr(domain.getDictDataEnumValueJson()));
//                item.add(
//                    ObjectUtils.getDisplayString(
//                        departmentMap.get(domain.getDepartmentId()).getOwnerName()));
                String date = DateUtil.formatDate(domain.getUpdateTime());
                item.add(StringUtils.isBlank(date) ? "" : date);
                String createUserName = userMap.get(domain.getCreatorId());
                item.add(StringUtils.isBlank(createUserName) ? "" : createUserName);
                dataList.add(item);
            });
        EasyExcelUtil.exportExcel(response, "字典", dataList);
    }

    @Override
    public List<DictionaryDomain> getAllDictionary(Long projectId) {

        LambdaQueryWrapper<DictionaryEntity> query = new QueryWrapper<DictionaryEntity>().lambda();
        query.eq(DictionaryEntity::getProjectId, projectId).eq(DictionaryEntity::getRowState, 1);
        List<DictionaryEntity> multi = dictionaryMapper.selectList(query);
        List<DictionaryDomain> dictionaryDomains = dictionaryDomainMapper.map(multi);
        return dictionaryDomains;
    }

    @Override
    public List<DictionaryDomain> getPublishedDictionaries(Long projectId) {
        LambdaQueryWrapper<DictionaryEntity> query = new LambdaQueryWrapper<DictionaryEntity>()
            .eq(Objects.nonNull(projectId), DictionaryEntity::getProjectId, projectId)
            .eq(DictionaryEntity::getRowState, 1)
            .eq(DictionaryEntity::getReleaseStatus, 1);
        return dictionaryDomainMapper.map(dictionaryMapper.selectList(query));
    }

    @Override
    public List<ThemeDomain> getThemesForStand(Long projectId) {

        List<ThemeDomain> result = themeService.treeThemes(projectId, "公共层");
        result.stream()
            .filter(themeDomain -> "0".equals(themeDomain.getPid()))
            .forEach(
                i -> {
                    i.setThemeName("全部分组");
                });
        return result;
    }

    @Override
    public List<DictionaryDomain> getRealeseDic(Long projectId) {

        LambdaQueryWrapper<DictionaryEntity> query = new QueryWrapper<DictionaryEntity>().lambda();
        query
            .eq(Objects.nonNull(projectId), DictionaryEntity::getProjectId, projectId)
            .eq(DictionaryEntity::getRowState, 1)
            .eq(DictionaryEntity::getReleaseStatus, 1);

        return dictionaryDomainMapper.map(dictionaryMapper.selectList(query));
    }

    @Override
    public List<DictionaryDomain> getRealeseDicDetail(String dictNameEn, String dictNameCn) {
        //    Query query = new Query();
        //
        //    if (dictNameEn != null || dictNameCn != null) {
        //
        //      Criteria criteria = new Criteria();
        //      criteria.orOperator(
        //          Criteria.where("rowState")
        //              .is(1)
        //              .and("releaseStatus")
        //              .is(1)
        //              .and("dictNameEn")
        //              .regex("^.*" + dictNameEn + ".*$"),
        //          Criteria.where("rowState")
        //              .is(1)
        //              .and("releaseStatus")
        //              .is(1)
        //              .and("dictNameCn")
        //              .regex("^.*" + dictNameCn + ".*$"));
        //
        //      query.addCriteria(criteria);
        //    }
        LambdaQueryWrapper<DictionaryEntity> query = new QueryWrapper<DictionaryEntity>().lambda();
        if (dictNameEn != null || dictNameCn != null) {
            query
                .and(
                    i ->
                        i.eq(DictionaryEntity::getRowState, 1)
                            .eq(DictionaryEntity::getReleaseStatus, 1)
                            .like(DictionaryEntity::getDictNameEn, dictNameEn))
                .or()
                .and(
                    i ->
                        i.eq(DictionaryEntity::getRowState, 1)
                            .eq(DictionaryEntity::getReleaseStatus, 1)
                            .like(DictionaryEntity::getDictNameCn, dictNameCn));
        }
        return dictionaryDomainMapper.map(dictionaryMapper.selectList(query));
    }

    /**
     * @param themeId
     * @description : 根据主题id查询
     * @author : tinglan.ys
     * @date : 2022/4/28
     */
    @Override
    public List<DictionaryEntity> getDictionaryByThemeId(Long themeId) {
        LambdaQueryWrapper<DictionaryEntity> query = new QueryWrapper<DictionaryEntity>().lambda();
        query.eq(DictionaryEntity::getDictDirId, themeId).eq(DictionaryEntity::getRowState, 1);
        List<DictionaryEntity> multi = dictionaryMapper.selectList(query);
        return multi;
    }

    @Override
    public List<DictionaryDomain> getDictionaryByFiledName(List<String> filedNames, Long projectId) {

        LambdaQueryWrapper<DictionaryEntity> query = new QueryWrapper<DictionaryEntity>().lambda();
        query
            .eq(DictionaryEntity::getProjectId, projectId)
            .eq(DictionaryEntity::getReleaseStatus, 1)
            .eq(DictionaryEntity::getRowState, 1);
        List<DictionaryEntity> dictionarys = dictionaryMapper.selectList(query);

        ArrayList<DictionaryEntity> matchDics = Lists.newArrayList();
        filedNames.forEach(
            fileName -> {
                List<DictionaryEntity> item =
                    dictionarys.stream()
                        .filter(dic -> fileName.equalsIgnoreCase(dic.getDictNameEn()))
                        .collect(Collectors.toList());
                matchDics.addAll(item);
            });
        List<DictionaryDomain> dictionaryDomains = dictionaryDomainMapper.map(matchDics);
        dictionaryDomains.stream().forEach(i -> i.dictDataEnumValueJsonToEnumKeys());
        return dictionaryDomains;
    }

    @Override
    public List<DictionaryDomain> getListByPage(Long projectId, Integer pageSize, Integer pageNum) {

        Page<DictionaryEntity> page =
            this.page(
                new Page<>(pageNum, pageSize),
                new LambdaQueryWrapper<DictionaryEntity>()
                    .eq(DictionaryEntity::getProjectId, projectId)
                    .eq(DictionaryEntity::getRowState, 1));
        List<DictionaryEntity> records = page.getRecords();
        return dictionaryDomainMapper.map(records);
    }

    @Override
    public List<DictionaryEntity> getListDicAll(Long projectId) {

        return dictionaryMapper.getDicDetail(projectId);
    }

    private String getRangeStr(String dictDataRangeJson) {
        if (StringUtils.isBlank(dictDataRangeJson) || Objects.equals(dictDataRangeJson, "{}")) {
            return "";
        }
        try {
            Map linkedHashMap = JSON.parseObject(dictDataRangeJson, Map.class);
            Object s1 = linkedHashMap.get("valueCondition1");
            Object s2 = linkedHashMap.get("valueRange1");
            Object s3 = linkedHashMap.get("valueJudge");
            Object s4 = linkedHashMap.get("valueCondition2");
            Object s5 = linkedHashMap.get("valueRange2");

            return s1 + " " + s2 + " " + s3 + " " + s4 + " " + s5;

        } catch (Exception e) {
            return "";
        }
    }

    private String getKeyValueStr(String bizPropertiesJson) {
        if (StringUtils.isBlank(bizPropertiesJson)) {
            return "";
        }
        try {
            List<KeyValueDomain> domainList = JSON.parseArray(bizPropertiesJson, KeyValueDomain.class);
            if (CollectionUtils.isEmpty(domainList)) {
                return "";
            }
            StringBuilder sb = new StringBuilder();
            domainList.forEach(
                domain -> {
                    if (sb.length() > 0) {
                        sb.append(",");
                    }
                    sb.append(domain.getKey()).append(":").append(domain.getValue());
                });
            return sb.toString();
        } catch (Exception e) {
            return "";
        }
    }

    private String getGroupName(Long groupId, Map<Long, ThemeDomain> groupMap) {
        List<String> dirList = new ArrayList<>();
        Long cur = groupId;
        while (true) {
            ThemeDomain curGroup = groupMap.get(cur);
            if (curGroup == null) {
                break;
            }
            dirList.add(curGroup.getThemeName());
            cur = curGroup.getPid();
        }
        StringBuilder sb = new StringBuilder();
        for (int i = dirList.size() - 1; i >= 0; i--) {
            if (sb.length() > 0) {
                sb.append("/");
            }
            sb.append(dirList.get(i));
        }
        return sb.toString();
    }

    public static void main(String[] args) {
    }
}
